import yaml
from PIL import Image, ImageDraw, ImageFont
import cairosvg
import io
import re
import os

def load_config(config_path='configs/configphone.yml'):
    """Load configuration from a YAML file."""
    with open(config_path, 'r', encoding='utf-8') as f:
        return yaml.safe_load(f)

def draw_grid(draw, width, height, step, color):
    """Draw a grid on the background."""
    for i in range(0, width, step):
        draw.line([(i, 0), (i, height)], fill=color, width=1)
    for i in range(0, height, step):
        draw.line([(0, i), (width, i)], fill=color, width=1)

def render_svg_to_png(svg_content, size):
    """Render SVG content to a PNG image."""
    return cairosvg.svg2png(bytestring=svg_content.encode('utf-8'), output_width=size, output_height=size)

def draw_text_with_shadow(draw, text, position, font, fill, shadow_color, shadow_offset):
    """Draw text with a shadow."""
    try:
        # Ensure shadow_offset values are numeric before using them
        shadow_position = (position[0] + float(shadow_offset[0]), position[1] + float(shadow_offset[1]))
        draw.text(shadow_position, text, font=font, fill=shadow_color)
    except (ValueError, TypeError, IndexError):
        # If shadow_offset is invalid, print a warning and skip drawing the shadow
        print(f"Warning: Invalid shadow_offset value: {shadow_offset}. Skipping shadow.")

    # Draw the main text regardless of whether the shadow was successful
    draw.text(position, text, font=font, fill=fill)


def draw_styled_title(draw, config, fonts, text, image_width):
    """
    Draw a title with support for bold text.
    Use **bold text** to mark text that needs to be bold.
    """
    title_config = config['title']
    text_parts = re.split(r'(\*\*.*?\*\*)', text)
    
    total_width = 0
    render_parts = []

    # 1. Calculate total width and prepare render parts
    for part in text_parts:
        if part.startswith('**') and part.endswith('**'):
            content = part[2:-2]
            font = fonts['bold']
            width = font.getbbox(content)[2]
            render_parts.append({'content': content, 'font': font, 'bold': True})
        else:
            content = part
            font = fonts['regular']
            width = font.getbbox(content)[2]
            render_parts.append({'content': content, 'font': font, 'bold': False})
        total_width += width
        
    # 2. Draw text
    x = (image_width - total_width) / 2
    y = title_config['y_position']

    for part in render_parts:
        font = part['font']
        content = part['content']
        color = title_config['bold_font_color'] if part['bold'] else title_config['font_color']
        
        shadow_offset = title_config.get('shadow_offset', [0, 0])
        shadow_color = title_config.get('shadow_color', '#00000000')

        draw_text_with_shadow(
            draw,
            content,
            (x, y),
            font,
            fill=color,
            shadow_color=shadow_color,
            shadow_offset=shadow_offset
        )
        x += font.getbbox(content)[2]


def draw_footnote(draw, config, font, image_width):
    """Draw the footnote."""
    footnote_config = config['footnote']
    if not footnote_config['enabled']:
        return

    text = footnote_config['text']
    y_pos = footnote_config['y_position']
    padding = footnote_config['padding']
    
    bbox = font.getbbox(text)
    text_width = bbox[2]
    text_height = bbox[3] - bbox[1]

    rect_width = text_width + padding * 2
    rect_height = text_height + padding * 2
    
    rect_x = (image_width - rect_width) / 2
    rect_y = y_pos

    # Draw background rectangle
    draw.rectangle(
        [rect_x, rect_y, rect_x + rect_width, rect_y + rect_height],
        fill=footnote_config['background_color']
    )

    # Draw text
    text_x = rect_x + padding
    text_y = rect_y + padding + (rect_height - padding*2 - text_height) / 2 - bbox[1]
    draw.text(
        (text_x, text_y),
        text,
        font=font,
        fill=footnote_config['font_color']
    )

def get_next_filename(output_dir, text):
    """Gets the next available filename by incrementing a counter."""
    os.makedirs(output_dir, exist_ok=True)
    
    clean_text = re.sub(r'[\*\s\\/:"?<>|]+', '', text)
    clean_text = clean_text.replace('**', '')

    existing_files = os.listdir(output_dir)
    max_index = 0
    for f in existing_files:
        match = re.match(r'(\d+)__.*\.png', f)
        if match:
            max_index = max(max_index, int(match.group(1)))
    
    new_index = max_index + 1
    output_filename = f"{new_index}__{clean_text}.png"
    return os.path.join(output_dir, output_filename)


def generate_image(config, text, output_path=None):
    """
    Generate a single image from a configuration dictionary and save it.
    """
    
    image = Image.new('RGBA', (int(config['width']), int(config['height'])), config['background_color'])
    draw = ImageDraw.Draw(image)

    # Fonts need to be loaded here because they depend on font sizes in the config
    fonts = {
        'regular': ImageFont.truetype(config['fonts']['regular'], int(config['title']['font_size'])),
        'bold': ImageFont.truetype(config['fonts']['bold'], int(config['title']['font_size'])),
        'footnote': ImageFont.truetype(config['fonts']['regular'], int(config['footnote']['font_size']))
    }

    grid_config = config.get('grid', {})
    if grid_config.get('enabled'):
        draw_grid(draw, int(config['width']), int(config['height']), int(grid_config.get('step', 50)), grid_config.get('line_color', '#D3D3D3'))

    svg_config = config.get('svg', {})
    if svg_config.get('content'):
        size = int(svg_config.get('size', 200))
        png_data = render_svg_to_png(svg_config['content'], size)
        svg_image = Image.open(io.BytesIO(png_data))
        svg_x = (int(config['width']) - svg_image.width) // 2
        svg_y = int(svg_config.get('y_position', 100)) - svg_image.height // 2
        image.paste(svg_image, (svg_x, svg_y), svg_image)

    title_config = config.get('title', {})
    if title_config and text:
        draw_styled_title(draw, config, {'regular': fonts['regular'], 'bold': fonts['bold']}, text, int(config['width']))

    footnote_config = config.get('footnote', {})
    if footnote_config.get('enabled'):
        draw_footnote(draw, config, fonts['footnote'], int(config['width']))

    # If output_path is provided, save it there. Otherwise, just return the image object.
    if output_path:
        image.save(output_path)
        print(f"Image generated: {output_path}")
    
    return image

def main():
    """Main function for command-line execution"""
    print("--- Start main function ---")
    
    # Example: Load 'phone' config and generate images for texts specified in it
    config_file = 'configs/configphone.yml'
    config = load_config(config_file)
    print(f"--- Config '{config_file}' loaded ---")
    
    output_dir = config.get('output_dir', 'output/')
    os.makedirs(output_dir, exist_ok=True)
    print(f"--- Output directory '{output_dir}' ensured ---")
    
    texts = config.get('title', {}).get('texts_to_generate', [])
    if not texts:
        print("--- No texts found in 'texts_to_generate' section of the config. ---")
        return

    print(f"--- Found {len(texts)} texts to generate images for ---")
    for text in texts:
        print(f"--- Generating image for text: '{text}' ---")
        # Get a unique filename
        output_path = get_next_filename(output_dir, text)
        # Generate and save the image
        generate_image(config, text, output_path)
        
    print("--- Finished image generation loop ---")

if __name__ == '__main__':
    main()
